package sc.prototype.pfs.eventnotify.collector.impl;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.util.Assert;

import sc.prototype.pfs.eventnotify.Configs;
import sc.prototype.pfs.eventnotify.api.UniNotice;
import sc.prototype.pfs.eventnotify.collector.ContentCollector;
import sc.prototype.pfs.eventnotify.excep.CollectContentException;
import sc.prototype.pfs.eventnotify.model.NotifyConfig;
import sc.prototype.pfs.eventnotify.model.NotifyContext;
import sc.prototype.pfs.eventnotify.model.ParamKey;
import sc.prototype.pfs.eventnotify.util.ExtensionHelper;
import sc.prototype.pfs.eventnotify.util.HashHelper;

/**
 * 通知内容采集器
 */
public abstract class BaseContentCollector implements ContentCollector {

    /** 采集器名称 */
    @Override
    public abstract String getName();

    /** 采集门面
     * @throws CollectContentException */
    @Override
    public UniNotice collect(NotifyConfig config, NotifyContext context) throws CollectContentException {
        try {
            UniNotice notice = processCollect(config, context);
            validate(notice);
            fillCheckCode(notice, config, context);
            return notice;
        } catch (Exception e) {
            throw new CollectContentException(config + "", e);
        }
    }

    /**
     * 各采集器实现方法
     * @return noticeType和noticeContent不可为null；checkCode如果为null则会自动进行计算，否则不再计算
     */
    public abstract UniNotice processCollect(NotifyConfig config, NotifyContext context);

    public void validate(UniNotice notice) {
        Assert.notNull(notice, "采集结果（统一通知消息）不可为空！");
        Assert.notNull(notice.getNoticeType(), "采集结果（统一通知消息）：消息类型不可为null！");
        Assert.notNull(notice.getNoticeContent(), "采集结果（统一通知消息）：消息内容不可为null！");
    }

    public void fillCheckCode(UniNotice notice, NotifyConfig config, NotifyContext context)
            throws NoSuchAlgorithmException, UnsupportedEncodingException {
        if (notice.getCheckCode() != null) {
            return;
        }
        CollectorExtensionHelper helper = new CollectorExtensionHelper(config, context);
        String hashMessage = notice.getNoticeType() + notice.getNoticeContent() + helper.getSalt();
        String checkCode = HashHelper.hash(helper.getHashType(), hashMessage, Configs.INS.DEFAULT_ENCODING);
        notice.setCheckCode(checkCode);
    }

    public static class CollectorExtensionHelper extends ExtensionHelper {

        public CollectorExtensionHelper(NotifyConfig config, NotifyContext context) {
            super(config, context);
        }

        public String getHashType() {
            return get(HASH_TYPE, Configs.INS.HASH_TYPE, true);
        }

        public String getSalt() {
            return get(HASH_SALT, false);
        }
    }

    public static final ParamKey HASH_TYPE, HASH_SALT;
    public static final ArrayList<ParamKey> PARAM_KEYS;
    static {
        HASH_TYPE = new ParamKey("HASH_TYPE", "生成消息校验码的哈希算法", "(?i)^MD5$", false);
        HASH_SALT = new ParamKey("HASH_SALT", "哈希算法使用的调料", ".*", true);
        PARAM_KEYS = new ArrayList<ParamKey>();
        PARAM_KEYS.add(HASH_TYPE);
    }

    /** 可用扩展参数列表，子类需要可能需要继承父类的扩展参数 */
    @SuppressWarnings("unchecked")
    @Override
    public List<ParamKey> getExtParamKeys() {
        return (List<ParamKey>) PARAM_KEYS.clone();
    }

    @Override
    public String toString() {
        return super.toString() + "@" + getName();
    }
}
